#include <iostream>
#include <unistd.h>
#include <cassert>
#include <vector>
#include <string>
#include "Task.hpp"
#include <sys/types.h>
#include <sys/wait.h>
const int num = 5;
static int numid = 1;

// os要管理很多信道，因此先描述，再组织。
class channel
{
public:
    channel(int fd, int id)
        : ctrlfd(fd), workid(id)
    {
        name = "channel-" + std::to_string(numid++);
    }

public:
    int ctrlfd;
    int workid;
    std::string name;
};

void work()
{
    // int cnt = 5;
    // while(cnt--)
    // {
    //     sleep(1);
    //     std::cout << "I am a child , id : " << getpid() << std::endl;
    // }
    int code = 0;
    while (true)
    {
        ssize_t n = read(0, &code, sizeof(code));
        if (n == sizeof(code))
        {
            if (!init.checkCode(code))
                continue;
            init.runTask(code);
        }
        else if (n == 0)
        {
            std::cout << "father no write task" << std::endl;
            break;
        }
        else
        {
            // do nothing
        }
    }
    std::cout << "child quit" << std::endl;
}

void CreateChannels(std::vector<channel> *c)
{
    std::vector<int> old;
    for (int i = 0; i < num; i++)
    {
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n == 0); // 成功返回0,
        (void)n;

        pid_t id = fork();
        assert(id != -1);
        // 父写，子读，关闭相关fd，形成单向信道
        if (id == 0)
        {
            if (!old.empty())
            {
                for (auto fd : old)
                {
                    close(fd);
                }
            }
            // child
            close(pipefd[1]);
            // 输入重定向
            dup2(pipefd[0], 0);
            work();
            exit(0);
        }

        // father
        close(pipefd[0]);
        c->push_back(channel(pipefd[1], id));
        old.push_back(pipefd[1]);
    }
}

void PrintDebug(const std::vector<channel> &channels)
{
    for (const auto &c : channels)
    {
        std::cout << c.name << " fd : " << c.ctrlfd << "workid : " << c.workid << std::endl;
    }
}

void SendCommand(const std::vector<channel> &c, int flag, int num = -1)
{
    int pos = 0;
    while (true)
    {
        // 2.1 选择任务
        int command = init.selectTask();
        // 2.2 选择信道
        const auto channel = c[pos++];
        pos %= c.size();
         // debug
        std::cout << "send command " << init.ToDesc(command) << "[" << command << "]"
                  << " in "
                  << channel.name << " worker is : " << channel.workid << std::endl;
        // 2.3 发送任务
        write(channel.ctrlfd, &command, sizeof(command));
        // 退出
        if (!flag)
        {
            if (--num <= 0)
            {
                break;
            }
        }
    }
    std::cout << "SendCommand done..." << std::endl;
}

void ReleaseChannels(std::vector<channel> c)
{
    // for (auto &channel : c)
    // {
    //     close(channel.ctrlfd);
    // }
    // for (auto &channel : c)
    // {
    //     int rid = waitpid(channel.workid, nullptr, 0);
    //     if (rid == channel.workid)
    //     {
    //         std::cout << "wait child: " << channel.workid << " success" << std::endl;
    //     }
    // }

    for (auto &channel : c)
    {
        close(channel.ctrlfd);
        int rid = waitpid(channel.workid, nullptr, 0);
    }
    // version 2
    // int num = c.size() - 1;
    // for (; num >= 0; num--)
    // {
    //     close(c[num].ctrlfd);
    //     waitpid(c[num].workerid, nullptr, 0);
    // }
}

int main()
{
    std::vector<channel> channels;
    // 1.创建信道，创建进程
    CreateChannels(&channels);
    // PrintDebug(channels);

    // 2.发送任务
    const bool g_always_loop = true;
    SendCommand(channels, !g_always_loop, 10);
    // 3.回收任务
    ReleaseChannels(channels);

    return 0;
}